﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;

namespace Linxiao.SP.Tools.GroupUsersMover.Library
{
    /// <summary>
    /// GroupUsersMover class encapsulates the business logics to move groups/users between sites
    /// </summary>
    public class GroupUsersManager
    {
        /// <summary>
        /// Check if the same group already exists and associated with the destination site
        /// </summary>
        /// <param name="group"></param>
        /// <param name="site"></param>
        /// <returns></returns>
        public static bool HasGroupAssociated(string group, GUMSite site)
        {
            bool hasGroupAssociated = false;
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                if (HasGroup(group, site))
                {
                    SPGroup spGroup = site.GetSite().SiteGroups[group];
                    if (spGroup != null)
                    {
                        foreach (SPRoleAssignment roleAssignment in site.GetSite().RoleAssignments)
                        {
                            if (roleAssignment.Member.Name.Equals(spGroup.Name))
                                hasGroupAssociated = true;
                        }
                    }
                }

            });
            return hasGroupAssociated;
        }

        /// <summary>
        /// check if the group exists in the site collection
        /// </summary>
        /// <param name="group"></param>
        /// <param name="site"></param>
        /// <returns></returns>
        public static bool HasGroup(string group, GUMSite site)
        {
            foreach (SPGroup spGroup in site.GetSite().SiteGroups)
            { 
                if (spGroup.Name.Equals(group))
                    return true;
            }
            return false;

        }

        /// <summary>
        /// check if a user already exists in a group
        /// </summary>
        /// <param name="user"></param>
        /// <param name="group"></param>
        /// <param name="site"></param>
        /// <returns></returns>
        public static bool HasUser(string user, string group, GUMSite site)
        {
            if (HasGroup(group, site))
            {
                SPGroup spGroup = site.GetSite().SiteGroups[group];
                if (spGroup != null)
                {
                    if (spGroup.Users[user] != null)
                        return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Remove a group role assignment from a group
        /// </summary>
        /// <param name="site"></param>
        /// <param name="group"></param>
        public static void RemoveGroupRoleAssignment(GUMSite site, string group)
        {
            if (HasGroupAssociated(group, site))
            {
                SPGroup spGroup = site.GetSite().SiteGroups[group];
                site.GetSite().RoleAssignments.Remove(spGroup);
                site.GetSite().Update();
            }
        }

        /// <summary>
        /// Remvoe a group from the site collection
        /// </summary>
        /// <param name="site"></param>
        /// <param name="group"></param>
        public static void RemoveGroup(GUMSite site, string group)
        {
            if (HasGroup(group, site))
            {
                site.GetSite().SiteGroups.Remove(group);
                site.GetSite().Update();
            }
        }

        /// <summary>
        /// Remvoe a user from a group
        /// </summary>
        /// <param name="site"></param>
        /// <param name="user"></param>
        /// <param name="group"></param>
        public static void RemoveUser(GUMSite site, string user, string group)
        {
            if (HasGroup(group, site))
            {
                if (HasUser(user, group, site))
                {
                    site.GetSite().SiteGroups[group].Users.Remove(user);
                }
            }
        }

        public static void MoveUser(string userToMove, string destinationGroup, GUMSite destinationSite)
        {

        }

        /// <summary>
        /// Move a group
        /// </summary>
        /// <param name="groupToMove"></param>
        /// <param name="sourceSite"></param>
        /// <param name="destinationSite"></param>
        /// <returns></returns>
        public static SPGroup MoveGroup(string groupToMove, GUMSite sourceSite, GUMSite destinationSite)
        {
            if (HasGroup(groupToMove, destinationSite))
                throw new Exception("Failed to move group as the group already exists in destination site.");

            if (!HasGroup(groupToMove, sourceSite))
                throw new Exception("Failed to move group as the group does not exist in the source site");

            SPGroup destinationGroup = null; ;

            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                //get the source group
                SPGroup sourceGroup = sourceSite.GetSite().SiteGroups[groupToMove];

                //get the current user
                SPUser adminUser = destinationSite.GetSite().CurrentUser;

                //add the destination group
                destinationSite.GetSite().SiteGroups.Add(groupToMove, adminUser, null, sourceGroup.Description);
                destinationGroup = destinationSite.GetSite().SiteGroups[groupToMove];

                StringBuilder sb = new StringBuilder();
                foreach (SPUser user in sourceGroup.Users)
                {
                    try
                    {
                        destinationGroup.Users.Add(user.LoginName, user.Email, user.Name, user.Notes);
                    }
                    catch (Exception ex)
                    {
                        sb.AppendLine(user.Name);
                    }
                }
                                
            });

            return destinationGroup;
        }

        /// <summary>
        /// Move a group association from source site to destination site
        /// </summary>
        /// <param name="groupToMove"></param>
        /// <param name="sourceSite"></param>
        /// <param name="destinationSite"></param>
        public static void MoveGroupRoleAssignment(string groupToMove, GUMSite sourceSite, GUMSite destinationSite)
        {
            if (HasGroupAssociated(groupToMove, destinationSite))
                throw new Exception("Failed to move group as the group already exists in destination site.");

            if (!HasGroup(groupToMove, sourceSite))
                throw new Exception("Failed to move group as the group does not exist in the source site");

            string errorMessage="";
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {

                //get the source group
                SPGroup sourceGroup = sourceSite.GetSite().SiteGroups[groupToMove];

                //add the destination group
                SPGroup destinationGroup = destinationSite.GetSite().SiteGroups[groupToMove];

                //get source role assignment
                SPRoleAssignment soureRoleAssignment = sourceSite.GetSite().RoleAssignments.GetAssignmentByPrincipal(sourceGroup);
                SPRoleAssignment destinationRoleAssignment = new SPRoleAssignment(destinationGroup);
                //get all role definition assigned to the source group
                foreach (SPRoleDefinition sourceRoleDefinition in soureRoleAssignment.RoleDefinitionBindings)
                {
                    SPRoleDefinition destinationRoleDefinition = destinationSite.GetSite().RoleDefinitions[sourceRoleDefinition.Name];
                    if (destinationRoleDefinition!=null)
                        destinationRoleAssignment.RoleDefinitionBindings.Add(destinationRoleDefinition);
                }

                try
                {
                    destinationSite.GetSite().RoleAssignments.Add(destinationRoleAssignment);
                }
                catch (Exception ex)
                {
                    errorMessage = string.Format("Cannot edit user permission as the destination site is inheriting permission from parent site.");
                }

                destinationSite.GetSite().Update();
            });

            if (!string.IsNullOrEmpty(errorMessage))
            {
                throw new Exception(errorMessage);
            }
        
        }


    }
}
